
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @module byteBuffer
* @author: Hjava
* @description:
* @since: 2018-07-16 11:35:39
*/
/**
 * ByteBuffer
 * @module ByteBuffer
 * @author: wanghe02@meituan.com
 * Date: 15-4-20
 * Time: 下午12:00
 * @type {ByteBuffer}
 */
var long_1 = __webpack_require__(/*! _util/long */ "./src/core/utils/long.ts");
//define(['./long'], function (Long) {
// utfx-embeddable
/**
 * utfx-embeddable (c) 2014 Daniel Wirtz <dcode@dcode.io>
 * Released under the Apache License, Version 2.0
 * see: https://github.com/dcodeIO/utfx for details
 */
var utfx = function () {
    'use strict';
    /**
     * utfx namespace.
     * @inner
     * @type {!Object.<string,*>}.
     */
    var utfx = {};
    /**
     * Encodes UTF8 code points to UTF8 bytes.
     * @param {(!function():number|null) | number} src Code points source, either as a function returning the next code point
     *  respectively `null` if there are no more code points left or a single numeric code point.
     * @param {!function(number)} dst Bytes destination as a function successively called with the next byte
     */
    utfx.encodeUTF8 = function (src, dst) {
        var cp = null;
        if (typeof src === 'number') {
            cp = src;
            src = function () {
                return null;
            };
        }
        while (cp !== null || (cp = src()) !== null) {
            if (cp < 0x80) { //128
                dst(cp & 0x7F);
            }
            else if (cp < 0x800) { //2048
                dst(((cp >> 6) & 0x1F) | 0xC0);
                dst((cp & 0x3F) | 0x80);
            }
            else if (cp < 0x10000) { //65536
                dst(((cp >> 12) & 0x0F) | 0xE0);
                dst(((cp >> 6) & 0x3F) | 0x80);
                dst((cp & 0x3F) | 0x80);
            }
            else {
                dst(((cp >> 18) & 0x07) | 0xF0);
                dst(((cp >> 12) & 0x3F) | 0x80);
                dst(((cp >> 6) & 0x3F) | 0x80);
                dst((cp & 0x3F) | 0x80);
            }
            cp = null;
        }
    };
    /**
     * Decodes UTF8 bytes to UTF8 code points.
     * @param {!function():number|null} src Bytes source as a function returning the next byte respectively `null` if there
     *  are no more bytes left.
     * @param {!function(number)} dst Code points destination as a function successively called with each decoded code point.
     * @throws {RangeError} If a starting byte is invalid in UTF8
     * @throws {Error} If the last sequence is truncated. Has an array property `bytes` holding the
     *  remaining bytes.
     */
    utfx.decodeUTF8 = function (src, dst) {
        var a, b, c, d, fail = function (b) {
            b = b.slice(0, b.indexOf(null));
            var err = Error(b.toString());
            err.name = 'TruncatedError';
            err['bytes'] = b;
            throw err;
        };
        while ((a = src()) !== null) {
            if ((a & 0x80) === 0) {
                dst(a);
            }
            else if ((a & 0xE0) === 0xC0) {
                ((b = src()) === null) && fail([a, b]),
                    dst(((a & 0x1F) << 6) | (b & 0x3F));
            }
            else if ((a & 0xF0) === 0xE0) {
                ((b = src()) === null || (c = src()) === null) && fail([a, b, c]),
                    dst(((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F));
            }
            else if ((a & 0xF8) === 0xF0) {
                ((b = src()) === null || (c = src()) === null || (d = src()) === null) && fail([a, b, c, d]),
                    dst(((a & 0x07) << 18) | ((b & 0x3F) << 12) | ((c & 0x3F) << 6) | (d & 0x3F));
            }
            else {
                throw RangeError('Illegal starting byte: ' + a);
            }
        }
    };
    /**
     * Converts UTF16 characters to UTF8 code points.
     * @param {!function():number|null} src Characters source as a function returning the next char code respectively
     *  `null` if there are no more characters left.
     * @param {!function(number)} dst Code points destination as a function successively called with each converted code
     *  point.
     */
    utfx.UTF16toUTF8 = function (src, dst) {
        var c1, c2 = null;
        // while (true) {
        var flag = true;
        while (flag === true) {
            if ((c1 = c2 !== null ? c2 : src()) === null)
                break;
            if (c1 >= 0xD800 && c1 <= 0xDFFF) {
                if ((c2 = src()) !== null) {
                    if (c2 >= 0xDC00 && c2 <= 0xDFFF) {
                        dst((c1 - 0xD800) * 0x400 + c2 - 0xDC00 + 0x10000);
                        c2 = null;
                        continue;
                    }
                }
            }
            dst(c1);
        }
        if (c2 !== null)
            dst(c2);
    };
    /**
     * Converts UTF8 code points to UTF16 characters.
     * @param {(!function():number|null) | number} src Code points source, either as a function returning the next code point
     *  respectively `null` if there are no more code points left or a single numeric code point.
     * @param {!function(number)} dst Characters destination as a function successively called with each converted char code.
     * @throws {RangeError} If a code point is out of range
     */
    utfx.UTF8toUTF16 = function (src, dst) {
        var cp = null;
        if (typeof src === 'number')
            cp = src, src = function () {
                return null;
            };
        while (cp !== null || (cp = src()) !== null) {
            if (cp <= 0xFFFF)
                dst(cp);
            else
                cp -= 0x10000,
                    dst((cp >> 10) + 0xD800),
                    dst((cp % 0x400) + 0xDC00);
            cp = null;
        }
    };
    /**
     * Converts and encodes UTF16 characters to UTF8 bytes.
     * @param {!function():number|null} src Characters source as a function returning the next char code respectively `null`
     *  if there are no more characters left.
     * @param {!function(number)} dst Bytes destination as a function successively called with the next byte.
     */
    utfx.encodeUTF16toUTF8 = function (src, dst) {
        utfx.UTF16toUTF8(src, function (cp) {
            utfx.encodeUTF8(cp, dst);
        });
    };
    /**
     * Decodes and converts UTF8 bytes to UTF16 characters.
     * @param {!function():number|null} src Bytes source as a function returning the next byte respectively `null` if there
     *  are no more bytes left.
     * @param {!function(number)} dst Characters destination as a function successively called with each converted char code.
     * @throws {RangeError} If a starting byte is invalid in UTF8
     * @throws {Error} If the last sequence is truncated. Has an array property `bytes` holding the remaining bytes.
     */
    utfx.decodeUTF8toUTF16 = function (src, dst) {
        utfx.decodeUTF8(src, function (cp) {
            utfx.UTF8toUTF16(cp, dst);
        });
    };
    /**
     * Calculates the byte length of an UTF8 code point.
     * @param {number} cp UTF8 code point
     * @returns {number} Byte length
     */
    utfx.calculateCodePoint = function (cp) {
        return (cp < 0x80) ? 1 : (cp < 0x800) ? 2 : (cp < 0x10000) ? 3 : 4;
    };
    /**
     * Calculates the number of UTF8 bytes required to store UTF8 code points.
     * @param {(!function():number|null)} src Code points source as a function returning the next code point respectively
     *  `null` if there are no more code points left.
     * @returns {number} The number of UTF8 bytes required
     */
    utfx.calculateUTF8 = function (src) {
        var cp, l = 0;
        while ((cp = src()) !== null)
            l += utfx.calculateCodePoint(cp);
        return l;
    };
    /**
     * Calculates the number of UTF8 code points respectively UTF8 bytes required to store UTF16 char codes.
     * @param {(!function():number|null)} src Characters source as a function returning the next char code respectively
     *  `null` if there are no more characters left.
     * @returns {!Array.<number>} The number of UTF8 code points at index 0 and the number of UTF8 bytes required at index 1.
     */
    utfx.calculateUTF16asUTF8 = function (src) {
        var n = 0, l = 0;
        utfx.UTF16toUTF8(src, function (cp) {
            ++n;
            l += utfx.calculateCodePoint(cp);
        });
        return [n, l];
    };
    return utfx;
}();
/**
 * String.fromCharCode reference for compile-time renaming.
 * @type {function(...number):string}
 * @inner
 */
var stringFromCharCode = String.fromCharCode;
var ts = Object.prototype.toString;
/**
 * Creates a source function for a string.
 * @param {string} s String to read from
 * @returns {function():number|null} Source function returning the next char code respectively `null` if there are
 *  no more characters left.
 * @throws {TypeError} If the argument is invalid
 * @inner
 */
function stringSource(s) {
    var i = 0;
    return function () {
        return i < s.length ? s.charCodeAt(i++) : null;
    };
}
/**
 * Creates a destination function for a string.
 * @returns {function(number=):undefined|string} Destination function successively called with the next char code.
 *  Returns the final string when called without arguments.
 * @inner
 */
function stringDestination() {
    var cs = [], ps = [];
    return function () {
        if (arguments.length === 0)
            return ps.join('') + stringFromCharCode.apply(String, cs);
        if (cs.length + arguments.length > 1024)
            ps.push(stringFromCharCode.apply(String, cs)),
                cs.length = 0;
        Array.prototype.push.apply(cs, arguments);
    };
}
// function stringDestination(...res) {
//     var cs = [], ps = [];
//     return function () {
//         if (res.length === 0)
//             return ps.join('') + stringFromCharCode.apply(String, cs);
//         if (cs.length + res.length > 1024)
//             ps.push(stringFromCharCode.apply(String, cs)),
//             cs.length = 0;
//         cs.push(res);
//     };
// }
var ByteBuffer = function (capacityOrBuffer, littleEndian) {
    if (typeof capacityOrBuffer == 'number') {
        this.capacity = capacityOrBuffer;
        this.buffer = new ArrayBuffer(this.capacity);
    }
    else if (typeof capacityOrBuffer == 'object') {
        this.capacity = capacityOrBuffer.byteLength;
        this.buffer = capacityOrBuffer;
    }
    this.array = new Uint8Array(this.buffer);
    this.view = new DataView(this.buffer);
    /**
     * write pointer
     * @type {number}
     */
    this.writeOffset = 0;
    /**
     * read pointer
     * @type {number}
     */
    this.readOffset = 0;
    /**
     * last arraybuffer snapshot
     */
    this.snapshot = null;
    /**
     * Whether to use little endian byte order, defaults to `false` for big endian.
     * @type {boolean}
     * @expose
     */
    this.littleEndian = !!littleEndian;
};
/**
 * Metrics representing number of UTF8 characters. Evaluates to `c`.
 * @type {string}
 * @const
 * @expose
 */
ByteBuffer.METRICS_CHARS = 'c';
/**
 * Metrics representing number of bytes. Evaluates to `b`.
 * @type {string}
 * @const
 * @expose
 */
ByteBuffer.METRICS_BYTES = 'b';
/**
 *
 * @param buffer {ArrayBuffer|Array|ByteBuffer}
 * @returns {ByteBuffer}
 */
ByteBuffer.wrap = function (buffer) {
    if (ts.apply(buffer) === '[object ArrayBuffer]') {
        return new ByteBuffer(buffer);
    }
    else if (ts.apply(buffer) === '[object Array]') {
        return new ByteBuffer(new Uint8Array(buffer).buffer);
    }
    else if (buffer instanceof ByteBuffer) {
        return buffer;
    }
    else {
        // ie
        return new ByteBuffer(buffer);
    }
};
/**
 * @param str {string}
 * @returns {ArrayBuffer}
 */
ByteBuffer.strToBytes = function (str) {
    if (str == null || str == '') {
        return new ArrayBuffer(0);
    }
    var byteBuffer = new ByteBuffer(str.length * 3);
    byteBuffer.writeUTF8String(str);
    return byteBuffer.getBytes();
};
ByteBuffer.prototype = {
    /**
     * Writes two bytes unsigned integer.
     * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `2` if omitted.
     * @param {number} value Value to write
     * @returns {!ByteBuffer} this
     * @expose
     */
    putShort: function (value, offset) {
        var relative = typeof offset === 'undefined';
        if (relative)
            offset = this.writeOffset;
        offset += 2;
        var capacity3 = this.buffer.byteLength;
        if (offset > capacity3)
            this.resize((capacity3 *= 2) > offset ? capacity3 : offset);
        offset -= 2;
        this.view.setUint16(offset, value, this.littleEndian);
        if (relative)
            this.writeOffset += 2;
        return this;
    },
    /**
     * Reads two bytes unsigned integer.
     * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `2` if omitted.
     * @returns {number} Value read
     * @expose
     */
    popShort: function (offset) {
        var relative = typeof offset === 'undefined';
        if (relative)
            offset = this.readOffset;
        if (offset >= this.capacity) {
            return null;
        }
        var value = this.view.getUint16(offset, this.littleEndian);
        if (relative)
            this.readOffset += 2;
        return value;
    },
    /**
     * Writes four bytes containing the given short value
     * @param {number} value Value to write
     * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
     * @returns {!ByteBuffer} this
     */
    putInt: function (value, offset) {
        var relative = typeof offset === 'undefined';
        if (relative)
            offset = this.writeOffset;
        offset += 4;
        var capacity = this.buffer.byteLength;
        if (offset > capacity)
            this.resize((capacity *= 2) > offset ? capacity : offset);
        offset -= 4;
        this.view.setUint32(offset, value, this.littleEndian);
        if (relative)
            this.writeOffset += 4;
        return this;
    },
    /**
     * Reads four bytes unsigned integer.
     * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
     * @returns {number} Value read
     * @expose
     */
    popInt: function (offset) {
        var relative = typeof offset === 'undefined';
        if (relative)
            offset = this.readOffset;
        if (offset >= this.capacity) {
            return null;
        }
        var value = this.view.getUint32(offset, this.littleEndian);
        if (relative)
            this.readOffset += 4;
        return value;
    },
    /**
     * Reads one bytes unsigned integer.
     * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `1` if omitted.
     * @returns {number} Value read
     * @expose
     */
    readByte: function (offset) {
        var relative = typeof offset === 'undefined';
        if (relative)
            offset = this.readOffset;
        if (offset >= this.capacity) {
            return null;
        }
        var value = this.view.getUint8(offset);
        if (relative)
            this.readOffset += 1;
        return value;
    },
    /**
     * Writes one bytes unsigned integer.
     * @param {number} value Value to write
     * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `1` if omitted.
     * @returns {!ByteBuffer} this
     * @expose
     */
    writeByte: function (value, offset) {
        var relative = typeof offset === 'undefined';
        if (relative)
            offset = this.writeOffset;
        offset += 1;
        var capacity = this.buffer.byteLength;
        if (offset > capacity)
            this.resize((capacity *= 2) > offset ? capacity : offset);
        offset -= 1;
        this.view.setUint8(offset, value);
        if (relative)
            this.writeOffset += 1;
        return this;
    },
    /**
     *
     * @param {ArrayBuffer} value  Value to write
     * @param {number=} offset
     * @return {ByteBuffer}
     */
    putBytes: function (value, offset) {
        //TODO offset++
        var view = new DataView(value);
        for (var i = 0; i < value.byteLength; i++) {
            this.writeByte(view.getUint8(i));
        }
        return this;
    },
    popBytes: function (length, offset) {
        //TODO offset++
        var buffer = new ArrayBuffer(length);
        var view = new DataView(buffer);
        for (var i = 0; i < length; i++) {
            view.setUint8(i, this.readByte());
        }
        return buffer;
    },
    /**
     * Writes eight bytes unsigned integer.
     * @param {!Long} value Value to write
     * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
     * @returns {!ByteBuffer} this
     * @expose
     */
    putLong: function (value, offset) {
        var long = long_1.default.fromValue(value, true);
        if (typeof offset === 'number') {
            this.putInt(long.high, offset).putInt(long.low, offset + 4);
        }
        else {
            this.putInt(long.high).putInt(long.low);
        }
        return this;
    },
    /**
     * Reads eight bytes unsigned integer.use twice popInt instead of popLong
     * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
     * @returns {!Long} representing a 64 bit integer value
     * @expose
     */
    popLong: function (offset) {
        var value1, value2;
        if (typeof offset === 'number') {
            value1 = this.popInt(offset);
            value2 = this.popInt(offset + 4);
        }
        else {
            value1 = this.popInt();
            value2 = this.popInt();
        }
        return long_1.default.fromBits(value2, value1, true);
    },
    /**
     * Writes eight bytes float.
     * @param {number} value Value to write
     * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
     * @returns {!ByteBuffer} this
     * @expose
     */
    putDouble: function (value, offset) {
        var relative = typeof offset === 'undefined';
        if (relative)
            offset = this.writeOffset;
        offset += 8;
        var capacity = this.buffer.byteLength;
        if (offset > capacity)
            this.resize((capacity *= 2) > offset ? capacity : offset);
        offset -= 8;
        this.view.setFloat64(offset, value, this.littleEndian);
        if (relative)
            this.writeOffset += 8;
        return this;
    },
    /**
     * Reads a 64bit float.
     * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
     * @returns {number}
     * @expose
     */
    popDouble: function (offset) {
        var relative = typeof offset === 'undefined';
        if (relative)
            offset = this.readOffset;
        if (offset >= this.capacity) {
            return null;
        }
        var value = this.view.getFloat64(offset, this.littleEndian);
        if (relative)
            this.readOffset += 8;
        return value;
    },
    /**
     * Writes an UTF8 encoded string.
     * @param {string} str String to write
     * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} if omitted.
     * @returns {!ByteBuffer|number} this if offset is omitted, else the actual number of bytes written.
     * @expose
     */
    writeUTF8String: function (str, offset) {
        var relative = typeof offset === 'undefined';
        if (relative)
            offset = this.writeOffset;
        var k;
        var start = offset;
        k = utfx.calculateUTF16asUTF8(stringSource(str))[1];
        offset += k;
        var capacity4 = this.buffer.byteLength;
        if (offset > capacity4)
            this.resize((capacity4 *= 2) > offset ? capacity4 : offset);
        offset -= k;
        utfx.encodeUTF16toUTF8(stringSource(str), function (b) {
            this.view.setUint8(offset++, b);
        }.bind(this));
        if (relative) {
            this.writeOffset = offset;
        }
        return offset - start;
    },
    /**
     * Reads an UTF8 encoded string.
     * @param {number} length Number of characters or bytes to read.
     * @param {string=} metrics Metrics specifying what `length` is meant to count. Defaults to
     *  {@link METRICS_CHARS}.
     * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
     *  read if omitted.
     * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string
     *  read and the actual number of bytes read.
     * @expose
     */
    readUTF8String: function (length, metrics, offset) {
        if (typeof metrics === 'number') {
            offset = metrics;
            metrics = undefined;
        }
        var relative = typeof offset === 'undefined';
        if (relative)
            offset = this.readOffset;
        if (offset > this.capacity) {
            return null;
        }
        if (typeof metrics === 'undefined')
            metrics = ByteBuffer.METRICS_BYTES;
        var i = 0, start = offset, sd;
        if (metrics === ByteBuffer.METRICS_CHARS) {
            sd = stringDestination();
            utfx.decodeUTF8(function () {
                return i < length && offset < this.capacity ? this.view.getUint8(offset++) : null;
            }.bind(this), function (cp) {
                ++i;
                utfx.UTF8toUTF16(cp, sd);
            }.bind(this));
            if (i !== length)
                throw RangeError('Illegal range: Truncated data, ' + i + ' == ' + length);
            if (relative) {
                this.readOffset = offset;
                return sd();
            }
            else {
                return {
                    'string': sd(),
                    'length': offset - start
                };
            }
        }
        else if (metrics === ByteBuffer.METRICS_BYTES) {
            var k = offset + length;
            utfx.decodeUTF8toUTF16(function () {
                return offset < k ? this.view.getUint8(offset++) : null;
            }.bind(this), sd = stringDestination());
            if (offset !== k)
                throw RangeError('Illegal range: Truncated data, ' + offset + ' == ' + k);
            if (relative) {
                this.readOffset = offset;
                return sd();
            }
            else {
                return {
                    'string': sd(),
                    'length': offset - start
                };
            }
        }
        else
            throw TypeError('Unsupported metrics: ' + metrics);
    },
    /**
     * Resizes this ByteBuffer to be backed by a buffer of at least the given capacity. Will do nothing if already that
     *  large or larger.
     * @param {number} capacity Capacity required
     * @returns {!ByteBuffer} this
     * @throws {TypeError} If `capacity` is not a number
     * @throws {RangeError} If `capacity < 0`
     * @expose
     */
    resize: function (capacity) {
        if (this.buffer.byteLength < capacity) {
            var buffer = new ArrayBuffer(capacity);
            new Uint8Array(buffer).set(new Uint8Array(this.buffer));
            this.buffer = buffer;
            this.view = new DataView(this.buffer);
            this.array = new Uint8Array(this.buffer);
            this.capacity = capacity;
        }
        return this;
    },
    position: function (offset) {
        if (typeof offset == 'number') {
            this.writeOffset = offset;
        }
        else {
            return this.writeOffset;
        }
    },
    /**
     * Returns a copy of the buffer that contains this ByteBuffer's contents.
     * @returns {ArrayBuffer}
     */
    getBytes: function () {
        this.snapshot = new ArrayBuffer(this.writeOffset);
        new Uint8Array(this.snapshot).set(this.array.subarray(0, this.writeOffset));
        return this.snapshot;
    },
    /**
     * Returns a copy of the buffer that contains this ByteBuffer's contents.
     * @returns {Uint8Array}
     */
    getArray: function () {
        return this.array.subarray(0, this.writeOffset);
    }
};
exports.default = ByteBuffer;


//# sourceURL=webpack://MTDX/./src/core/utils/byteBuffer.ts?